# Check requisite packages are installed.
packages <- c(
  "plotly", 
  "dplyr",
  "cheddar",
  "igraph",
  "expm",
  "foreach",
  "iterators",
  "rootSolve",
  "RMTRCode2"
)
for (pkg in packages) {
  library(pkg, character.only = TRUE)
}

# Reserved Names
  communitiesAll <- NULL
  invasionsDirected <- NULL
  islandInteractionsOneEmptyTwo <- NULL
  islandInteractionsOneEmptyTwoWhich <- NULL
  islandInteractionsOneTwo <- NULL
  islandInteractionsOneTwoWhich <- NULL
  mats <- NULL
  paramFrame <- NULL
  plotScalingData <- NULL
  pools <- NULL

Overview

This is the third file in the LM1996-NumPoolCom set after QDatMake-2021-05 and Questions-2021-05. These files took data sets generated from Viking for purely exploitative Lotka-Volterra systems that were assembled according to the rules from Law’s and Morton’s 1996 and 1997 papers on community assembly. The first of these organised the data sets and identified their abundances before examining how the communities compared against each other from those assembled from the same pool. Three outcomes were usually observed: one community dominated, the communities persisted but with colonies from their neighbours (sustained by mass effects), or a hybrid community emerged and dominated. The second file looked at some of the properties of the various communities we were able to observe either from the initially assembly or from the comparison. Broadly, persistence was uncommon if the system was not assembled, and some systems collapsed down to states that we had not yet observed. Hybrid systems were invadable by the regional pool again (i.e. they lost the uninvadability property). Most systems did not seem to be invadable by the other systems, where invadable from the pool is growth from an infinitesimal, but it was not uncommon to be invadable either. There are multiple ways to measure indirect effects, but (indirect) mutualism is highly uncommon in the systems created. Competition appears to be not uncommon due to interactions between basal species through their consumers.

This file returns to the context of communities interacting with each other on islands (the comparison above). Here, we want to look at how the transition occurs and if we can determine why each outcome and property emerges.

Tabs

Load Data

ellipsisApply <- function(..., FUN) {
  lapply(as.list(...), FUN)
}

load("LM1996-NumPoolCom-QOut-2021-05.RData")
# Stop if not all are not null
stopifnot(all(unlist(ellipsisApply(
  FUN = function(bool) {!is.null(bool)},
  communitiesAll,
  invasionsDirected,
  islandInteractionsOneEmptyTwo,
  islandInteractionsOneEmptyTwoWhich,
  islandInteractionsOneTwo,
  islandInteractionsOneTwoWhich,
  mats,
  paramFrame,
  plotScalingData,
  pools,
))))
plotScaling <- plotly::plot_ly(
  plotScalingData,
  x = ~Basals,
  y = ~Consumers,
  z = ~CommunitySize,
  color = ~Dataset,
  colors = c("red", "blue", "black")
)

plotScaling <- plotly::add_markers(plotScaling)

plotScaling <- plotly::layout(
  plotScaling,
  scene = list(
    xaxis = list(type = "log"),
    yaxis = list(type = "log"),
    camera = list(
      eye = list(
        x = -1.25, y = -1.25, z = .05
      )
    )
  )
)

plotScaling

Dispersal based interactions

There are 6.5 sets of interactions which we place on either 2 or 3 islands to generate 82 communities by looking at islands before interaction, islands while interacting near steady-state, and islands after interaction has finished. Here, we will try to look at some examples as the system transitions from the first case to the second case. Which systems should we focus on? We choose systems reflecting the various outcomes we observe.

communitiesEX <- list(
  "HybridPersists" = communitiesAll[c( 4,  5),], # Hybrid Persists.
  "HybridCollapse" = communitiesAll[c( 4,  6),], # Hybrid Collapses to persist.
  "Extinction"     = communitiesAll[c(10, 11),], # Go Extinct when uncoupled.
  "Colonies"       = communitiesAll[c( 1,  2),], # They Colonise each other.
  "Domination"     = communitiesAll[c( 7,  8),]  # One community Dominates.
)
islandFUN <- function(i, dat, pool, mat, dmat) {
  temp <- dat[i, ]
  RMTRCode2::IslandDynamics(
    Pool = pool,
    InteractionMatrix = mat,
    Communities = c(
      list(temp$Communities[1]),
      rep("", nrow(dmat) - 2),
      temp$Communities[2]
    ),
    Populations = c(
      list(temp$CommunityAbund[1]),
      rep("", nrow(dmat) - 2),
      list(temp$CommunityAbund[2])
    ),
    DispersalPool = 0.0001,
    DispersalIsland = dmat,
    Times = c(seq(from = 0, to = 990, by = 10), # Slow high res start
              seq(from = 1000, to = 20000, by = 500)) # Faster low res.
  )
}
communitiesEXIslands <- lapply(communitiesEX, function(tib, pools, mats, dmat) {
  combn(
    nrow(tib), 2, 
    islandFUN,
    dat = tib, 
    pool = pools[[
      tib$DatasetID[1]
    ]][[tib$CombnNum[1]]],
    mat = mats[[
      tib$DatasetID[1]
    ]][[tib$CombnNum[1]]],
    dmat = dmat,
    simplify = FALSE
  )
}, pools = pools, mats = mats, dmat = matrix(c(
  0, 1, 0, # Island 2 -> 1
  1, 0, 1, # Island 1 -> 2, Island 3 -> 2
  0, 1, 0  # Island 2 -> 3
), nrow = 3, ncol = 3, byrow = TRUE))
communitiesEXIslandsLong <- lapply(
  communitiesEXIslands, 
  function(listtib, islandsNum) {
    speciesNum <- (ncol(listtib[[1]]) - 1) / islandsNum
    
    retval <- tidyr::pivot_longer(
      listtib[[1]] %>% as.data.frame, 
      cols = !"time", 
      names_to = "Species",
      values_to = "Abundance"
    ) %>% dplyr::mutate(
      Species = as.numeric(Species),
      Island = floor((Species - 1) / speciesNum),
      Species = ((Species - 1) %% speciesNum) + 1 # maps 1,2,3,4 %% 4 -> 1:4
    ) %>% dplyr::group_by(
      Species, Island
    ) %>% dplyr::mutate(
      Native = dplyr::first(Abundance > 0),
      Invasive = !Native
    ) %>% dplyr::ungroup() %>% dplyr::group_by(
      Species, time
    ) %>% dplyr::mutate(
      IslandsOccupied = sum(Abundance > 0)
    ) %>% dplyr::ungroup() %>% dplyr::group_by(
      Species, Island
    ) %>% dplyr::mutate(
      Endemic = Native & dplyr::first(IslandsOccupied) == 1,
      Type = dplyr::case_when(
        Endemic ~ "Endemic",
        Native ~ "Native",
        Invasive ~ "Invasive",
        TRUE ~ "Oops"
      )
    )
    
    return(retval)
  }, islandsNum = 3
)
communitiesEXIslandsImages <- lapply(
  communitiesEXIslandsLong,
  function(tib) {
    ggplot2::ggplot(
      tib,
      ggplot2::aes(
        x = time,
        y = Abundance,
        color = as.factor(Species),
        # linetype = Type,
        group = interaction(Species, Island)
      )
    ) + ggplot2::geom_line(
    ) + ggplot2::facet_grid(
      Island ~ Type
    ) + ggplot2::scale_y_log10(
    )
  }  
)

Cases

Hybrid Persists

communitiesEXIslandsImages[[1]]

Hybrid Collapse

communitiesEXIslandsImages[[2]]

Hybrid Extincts

communitiesEXIslandsImages[[3]]

Colonies

communitiesEXIslandsImages[[4]]

Domination

communitiesEXIslandsImages[[5]]
LS0tDQp0aXRsZTogIlRyYW5zaXRpb24gZnJvbSBJc29sYXRlcyB0byBIeWJyaWRzIDIwMjEtMDYiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQotLS0NCg0KYGBge3IgbGlicywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgQ2hlY2sgcmVxdWlzaXRlIHBhY2thZ2VzIGFyZSBpbnN0YWxsZWQuDQpwYWNrYWdlcyA8LSBjKA0KICAicGxvdGx5IiwgDQogICJkcGx5ciIsDQogICJjaGVkZGFyIiwNCiAgImlncmFwaCIsDQogICJleHBtIiwNCiAgImZvcmVhY2giLA0KICAiaXRlcmF0b3JzIiwNCiAgInJvb3RTb2x2ZSIsDQogICJSTVRSQ29kZTIiDQopDQpmb3IgKHBrZyBpbiBwYWNrYWdlcykgew0KICBsaWJyYXJ5KHBrZywgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQ0KfQ0KDQojIFJlc2VydmVkIE5hbWVzDQpjb21tdW5pdGllc0FsbCA8LSBOVUxMDQppbnZhc2lvbnNEaXJlY3RlZCA8LSBOVUxMDQppc2xhbmRJbnRlcmFjdGlvbnNPbmVFbXB0eVR3byA8LSBOVUxMDQppc2xhbmRJbnRlcmFjdGlvbnNPbmVFbXB0eVR3b1doaWNoIDwtIE5VTEwNCmlzbGFuZEludGVyYWN0aW9uc09uZVR3byA8LSBOVUxMDQppc2xhbmRJbnRlcmFjdGlvbnNPbmVUd29XaGljaCA8LSBOVUxMDQptYXRzIDwtIE5VTEwNCnBhcmFtRnJhbWUgPC0gTlVMTA0KcGxvdFNjYWxpbmdEYXRhIDwtIE5VTEwNCnBvb2xzIDwtIE5VTEwNCmBgYA0KDQojIE92ZXJ2aWV3DQpUaGlzIGlzIHRoZSB0aGlyZCBmaWxlIGluIHRoZSBgTE0xOTk2LU51bVBvb2xDb21gIHNldCBhZnRlciBgUURhdE1ha2UtMjAyMS0wNWAgYW5kIGBRdWVzdGlvbnMtMjAyMS0wNWAuIA0KVGhlc2UgZmlsZXMgdG9vayBkYXRhIHNldHMgZ2VuZXJhdGVkIGZyb20gVmlraW5nIGZvciBwdXJlbHkgZXhwbG9pdGF0aXZlIExvdGthLVZvbHRlcnJhIHN5c3RlbXMgdGhhdCB3ZXJlIGFzc2VtYmxlZCBhY2NvcmRpbmcgdG8gdGhlIHJ1bGVzIGZyb20gTGF3J3MgYW5kIE1vcnRvbidzIDE5OTYgYW5kIDE5OTcgcGFwZXJzIG9uIGNvbW11bml0eSBhc3NlbWJseS4NClRoZSBmaXJzdCBvZiB0aGVzZSBvcmdhbmlzZWQgdGhlIGRhdGEgc2V0cyBhbmQgaWRlbnRpZmllZCB0aGVpciBhYnVuZGFuY2VzIGJlZm9yZSBleGFtaW5pbmcgaG93IHRoZSBjb21tdW5pdGllcyBjb21wYXJlZCBhZ2FpbnN0IGVhY2ggb3RoZXIgZnJvbSB0aG9zZSBhc3NlbWJsZWQgZnJvbSB0aGUgc2FtZSBwb29sLg0KVGhyZWUgb3V0Y29tZXMgd2VyZSB1c3VhbGx5IG9ic2VydmVkOiBvbmUgY29tbXVuaXR5IGRvbWluYXRlZCwgdGhlIGNvbW11bml0aWVzIHBlcnNpc3RlZCBidXQgd2l0aCBjb2xvbmllcyBmcm9tIHRoZWlyIG5laWdoYm91cnMgKHN1c3RhaW5lZCBieSBtYXNzIGVmZmVjdHMpLCBvciBhIGh5YnJpZCBjb21tdW5pdHkgZW1lcmdlZCBhbmQgZG9taW5hdGVkLg0KVGhlIHNlY29uZCBmaWxlIGxvb2tlZCBhdCBzb21lIG9mIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSB2YXJpb3VzIGNvbW11bml0aWVzIHdlIHdlcmUgYWJsZSB0byBvYnNlcnZlIGVpdGhlciBmcm9tIHRoZSBpbml0aWFsbHkgYXNzZW1ibHkgb3IgZnJvbSB0aGUgY29tcGFyaXNvbi4NCkJyb2FkbHksIHBlcnNpc3RlbmNlIHdhcyB1bmNvbW1vbiBpZiB0aGUgc3lzdGVtIHdhcyBub3QgYXNzZW1ibGVkLCBhbmQgc29tZSBzeXN0ZW1zIGNvbGxhcHNlZCBkb3duIHRvIHN0YXRlcyB0aGF0IHdlIGhhZCBub3QgeWV0IG9ic2VydmVkLg0KSHlicmlkIHN5c3RlbXMgd2VyZSBpbnZhZGFibGUgYnkgdGhlIHJlZ2lvbmFsIHBvb2wgYWdhaW4gKGkuZS4gdGhleSBsb3N0IHRoZSB1bmludmFkYWJpbGl0eSBwcm9wZXJ0eSkuDQpNb3N0IHN5c3RlbXMgZGlkIG5vdCBzZWVtIHRvIGJlIGludmFkYWJsZSBieSB0aGUgb3RoZXIgc3lzdGVtcywgd2hlcmUgaW52YWRhYmxlIGZyb20gdGhlIHBvb2wgaXMgZ3Jvd3RoIGZyb20gYW4gaW5maW5pdGVzaW1hbCwgYnV0IGl0IHdhcyBub3QgdW5jb21tb24gdG8gYmUgaW52YWRhYmxlIGVpdGhlci4NClRoZXJlIGFyZSBtdWx0aXBsZSB3YXlzIHRvIG1lYXN1cmUgaW5kaXJlY3QgZWZmZWN0cywgYnV0IChpbmRpcmVjdCkgbXV0dWFsaXNtIGlzIGhpZ2hseSB1bmNvbW1vbiBpbiB0aGUgc3lzdGVtcyBjcmVhdGVkLg0KQ29tcGV0aXRpb24gYXBwZWFycyB0byBiZSBub3QgdW5jb21tb24gZHVlIHRvIGludGVyYWN0aW9ucyBiZXR3ZWVuIGJhc2FsIHNwZWNpZXMgdGhyb3VnaCB0aGVpciBjb25zdW1lcnMuIA0KDQpUaGlzIGZpbGUgcmV0dXJucyB0byB0aGUgY29udGV4dCBvZiBjb21tdW5pdGllcyBpbnRlcmFjdGluZyB3aXRoIGVhY2ggb3RoZXIgb24gaXNsYW5kcyAodGhlIGNvbXBhcmlzb24gYWJvdmUpLg0KSGVyZSwgd2Ugd2FudCB0byBsb29rIGF0IGhvdyB0aGUgdHJhbnNpdGlvbiBvY2N1cnMgYW5kIGlmIHdlIGNhbiBkZXRlcm1pbmUgd2h5IGVhY2ggb3V0Y29tZSBhbmQgcHJvcGVydHkgZW1lcmdlcy4NCg0KIyBUYWJzIHsudGFic2V0fQ0KDQojIyBMb2FkIERhdGENCg0KYGBge3IgbG9hZERhdH0NCmVsbGlwc2lzQXBwbHkgPC0gZnVuY3Rpb24oLi4uLCBGVU4pIHsNCiAgbGFwcGx5KGFzLmxpc3QoLi4uKSwgRlVOKQ0KfQ0KDQpsb2FkKCJMTTE5OTYtTnVtUG9vbENvbS1RT3V0LTIwMjEtMDUuUkRhdGEiKQ0KIyBTdG9wIGlmIG5vdCBhbGwgYXJlIG5vdCBudWxsDQpzdG9waWZub3QoYWxsKHVubGlzdChlbGxpcHNpc0FwcGx5KA0KICBGVU4gPSBmdW5jdGlvbihib29sKSB7IWlzLm51bGwoYm9vbCl9LA0KICBjb21tdW5pdGllc0FsbCwNCiAgaW52YXNpb25zRGlyZWN0ZWQsDQogIGlzbGFuZEludGVyYWN0aW9uc09uZUVtcHR5VHdvLA0KICBpc2xhbmRJbnRlcmFjdGlvbnNPbmVFbXB0eVR3b1doaWNoLA0KICBpc2xhbmRJbnRlcmFjdGlvbnNPbmVUd28sDQogIGlzbGFuZEludGVyYWN0aW9uc09uZVR3b1doaWNoLA0KICBtYXRzLA0KICBwYXJhbUZyYW1lLA0KICBwbG90U2NhbGluZ0RhdGEsDQogIHBvb2xzLA0KKSkpKQ0KYGBgDQoNCmBgYHtyIHRlc3RQbG90fQ0KcGxvdFNjYWxpbmcgPC0gcGxvdGx5OjpwbG90X2x5KA0KICBwbG90U2NhbGluZ0RhdGEsDQogIHggPSB+QmFzYWxzLA0KICB5ID0gfkNvbnN1bWVycywNCiAgeiA9IH5Db21tdW5pdHlTaXplLA0KICBjb2xvciA9IH5EYXRhc2V0LA0KICBjb2xvcnMgPSBjKCJyZWQiLCAiYmx1ZSIsICJibGFjayIpDQopDQoNCnBsb3RTY2FsaW5nIDwtIHBsb3RseTo6YWRkX21hcmtlcnMocGxvdFNjYWxpbmcpDQoNCnBsb3RTY2FsaW5nIDwtIHBsb3RseTo6bGF5b3V0KA0KICBwbG90U2NhbGluZywNCiAgc2NlbmUgPSBsaXN0KA0KICAgIHhheGlzID0gbGlzdCh0eXBlID0gImxvZyIpLA0KICAgIHlheGlzID0gbGlzdCh0eXBlID0gImxvZyIpLA0KICAgIGNhbWVyYSA9IGxpc3QoDQogICAgICBleWUgPSBsaXN0KA0KICAgICAgICB4ID0gLTEuMjUsIHkgPSAtMS4yNSwgeiA9IC4wNQ0KICAgICAgKQ0KICAgICkNCiAgKQ0KKQ0KDQpwbG90U2NhbGluZw0KYGBgDQoNCg0KIyMgRGlzcGVyc2FsIGJhc2VkIGludGVyYWN0aW9ucw0KDQpUaGVyZSBhcmUgYHIgbGVuZ3RoKGlzbGFuZEludGVyYWN0aW9uc09uZVR3bykvMmAgc2V0cyBvZiBpbnRlcmFjdGlvbnMgd2hpY2ggd2UgcGxhY2Ugb24gZWl0aGVyIDIgb3IgMyBpc2xhbmRzIHRvIGdlbmVyYXRlIGByIG5yb3coY29tbXVuaXRpZXNBbGwpYCBjb21tdW5pdGllcyBieSBsb29raW5nIGF0IGlzbGFuZHMgYmVmb3JlIGludGVyYWN0aW9uLCBpc2xhbmRzIHdoaWxlIGludGVyYWN0aW5nIG5lYXIgc3RlYWR5LXN0YXRlLCBhbmQgaXNsYW5kcyBhZnRlciBpbnRlcmFjdGlvbiBoYXMgZmluaXNoZWQuDQpIZXJlLCB3ZSB3aWxsIHRyeSB0byBsb29rIGF0IHNvbWUgZXhhbXBsZXMgYXMgdGhlIHN5c3RlbSB0cmFuc2l0aW9ucyBmcm9tIHRoZSBmaXJzdCBjYXNlIHRvIHRoZSBzZWNvbmQgY2FzZS4NCldoaWNoIHN5c3RlbXMgc2hvdWxkIHdlIGZvY3VzIG9uPyBXZSBjaG9vc2Ugc3lzdGVtcyByZWZsZWN0aW5nIHRoZSB2YXJpb3VzIG91dGNvbWVzIHdlIG9ic2VydmUuDQoNCjwhLS0gDQpTbyB0aGUgcHJvYmxlbSBpcyB0aGF0IHdlIGRvbid0IGtub3cgd2hlcmUgdGhlIHBhcmVudHMgYXJlIGZvciBlYWNoIHNldCBhbmQgd2UgZG9uJ3Qga25vdyB3aGljaCBzaWJsaW5nIGlzIHRoZSBpbXBvcnRhbnQgb25lIHRoYXQgd2Ugd2FudCB0byBmb2N1cyBvbi4NCkluIG1vc3QgY2FzZXMsIHRoaXMgaXMgZmluZSB0aG91Z2g7IG9ubHkgYDUgMmAgaGFzIG1vcmUgdGhhbiB0d28gcG9zc2libGUgcGFyZW50cy4NCklmIHdlIHN0cmlrZSBvdXQgdGhhdCBjYXNlLCB0aGVuIHdlIGhhdmUgZWl0aGVyIDIgaXNsYW5kcyBvciAzIGFuZCB0aGVuIHRoZSBudW1iZXIgb2YgaXNsYW5kcyB0aGVtc2VsdmVzIGFzIHRoZSBxdWVzdGlvbnMuDQpVbmZvcnR1bmF0ZWx5LCBvbmUgb2YgdGhlIG9uZXMgdGhhdCB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBpcyB0aGUgY29tbXVuaXR5IHRoYXQgcGVyc2lzdHMgZnJvbSBgNSAyYC4gU2luY2UgaXQgaGFzIDQ0LCBpdCBtdXN0IGJlIGRlc2NlbmRlZCBmcm9tIHRoZSBmaXJzdCwgYW5kIHNpbmNlIGl0IGhhcyAyNDcgaXQgbXVzdCBiZSBkZXNjZW5kZWQgZnJvbSB0aGUgc2Vjb25kLiBGdXJ0aGVybW9yZSwgc2luY2UgdGhlcmUgYXJlIDUgY29waWVzLCBpdCBtdXN0IGJlIG9idGFpbmFibGUgaW4gdGhlIHRocmVlIGlzbGFuZCBhbmQgdHdvIGlzbGFuZCBjYXNlcy4gVGhpcyBtdXN0IGJlIGluZGljZXMgNCBhbmQgNS4NCkFzIGZvciBhIHN5c3RlbSB0aGF0IGNvbGxhcHNlcyB3aXRob3V0IHRvdGFsIGV4dGluY3Rpb24sIHdlIG1pZ2h0IGFzIHdlbGwgZ28gYDUgMmAgd2l0aCB0aGUgZmlyc3QgYW5kIHRoaXJkLiBUaGlzIHR3byBhcHBlYXJzIHRvIG9jY3VyIGluIGJvdGggaXNsYW5kIG51bWJlciBjYXNlcy4gSW5kaWNlcyA0IGFuZCA2Lg0KRm9yIGEgc3lzdGVtIHRoYXQgaGFzIGNvbG9uaXNhdGlvbiB3ZSBjYW4gdXNlIHRoZSBgMiAzYCB0ZXN0IHN5c3RlbSBvbiBlaXRoZXIgc2V0dGluZy4gSW5kaWNlcyAxIGFuZCAyLg0KU2ltaWxhcmx5LCBmb3IgYSBzeXN0ZW0gdGhhdCBoYXMgZG9taW5hdGlvbiB3ZSBjYW4gdXNlIHRoZSBgNiAzYCB0ZXN0IHN5c3RlbSBvbiBlaXRoZXIgc2V0dGluZy4gSW5kaWNlcyA3IGFuZCA4Lg0KVGhpcyBnaXZlcyB1cyBvbmUgZG9taW5hbnQsIG9uZSBjb2xvbmlzaW5nLCBvbmUgY29sbGFwc2luZyBhbmQgc3Vydml2aW5nLCBvbmUgaHlicmlkaXNpbmcsIHNvIHdlIGFsc28gZ3JhYiBvbmUgY29sbGFwc2luZyB3aXRob3V0IHN1cnZpdmluZy4NCkZvciBzb21lIHZhcmlldHkgKGluIERhdGFzZXQpLCB3ZSBwaWNrIGAxNCAxYCBmb3IgdGhlIHNtYWxsZXN0IGNvbW11bml0eSBzaXplLiBJbmRpY2VzIDEwIGFuZCAxMS4NCi0tPg0KDQpgYGB7cn0NCmNvbW11bml0aWVzRVggPC0gbGlzdCgNCiAgIkh5YnJpZFBlcnNpc3RzIiA9IGNvbW11bml0aWVzQWxsW2MoIDQsICA1KSxdLCAjIEh5YnJpZCBQZXJzaXN0cy4NCiAgIkh5YnJpZENvbGxhcHNlIiA9IGNvbW11bml0aWVzQWxsW2MoIDQsICA2KSxdLCAjIEh5YnJpZCBDb2xsYXBzZXMgdG8gcGVyc2lzdC4NCiAgIkV4dGluY3Rpb24iICAgICA9IGNvbW11bml0aWVzQWxsW2MoMTAsIDExKSxdLCAjIEdvIEV4dGluY3Qgd2hlbiB1bmNvdXBsZWQuDQogICJDb2xvbmllcyIgICAgICAgPSBjb21tdW5pdGllc0FsbFtjKCAxLCAgMiksXSwgIyBUaGV5IENvbG9uaXNlIGVhY2ggb3RoZXIuDQogICJEb21pbmF0aW9uIiAgICAgPSBjb21tdW5pdGllc0FsbFtjKCA3LCAgOCksXSAgIyBPbmUgY29tbXVuaXR5IERvbWluYXRlcy4NCikNCmBgYA0KDQpgYGB7ciBpc2xhbmRGVU59DQppc2xhbmRGVU4gPC0gZnVuY3Rpb24oaSwgZGF0LCBwb29sLCBtYXQsIGRtYXQpIHsNCiAgdGVtcCA8LSBkYXRbaSwgXQ0KICBSTVRSQ29kZTI6OklzbGFuZER5bmFtaWNzKA0KICAgIFBvb2wgPSBwb29sLA0KICAgIEludGVyYWN0aW9uTWF0cml4ID0gbWF0LA0KICAgIENvbW11bml0aWVzID0gYygNCiAgICAgIGxpc3QodGVtcCRDb21tdW5pdGllc1sxXSksDQogICAgICByZXAoIiIsIG5yb3coZG1hdCkgLSAyKSwNCiAgICAgIHRlbXAkQ29tbXVuaXRpZXNbMl0NCiAgICApLA0KICAgIFBvcHVsYXRpb25zID0gYygNCiAgICAgIGxpc3QodGVtcCRDb21tdW5pdHlBYnVuZFsxXSksDQogICAgICByZXAoIiIsIG5yb3coZG1hdCkgLSAyKSwNCiAgICAgIGxpc3QodGVtcCRDb21tdW5pdHlBYnVuZFsyXSkNCiAgICApLA0KICAgIERpc3BlcnNhbFBvb2wgPSAwLjAwMDEsDQogICAgRGlzcGVyc2FsSXNsYW5kID0gZG1hdCwNCiAgICBUaW1lcyA9IGMoc2VxKGZyb20gPSAwLCB0byA9IDk5MCwgYnkgPSAxMCksICMgU2xvdyBoaWdoIHJlcyBzdGFydA0KICAgICAgICAgICAgICBzZXEoZnJvbSA9IDEwMDAsIHRvID0gMjAwMDAsIGJ5ID0gNTAwKSkgIyBGYXN0ZXIgbG93IHJlcy4NCiAgKQ0KfQ0KYGBgDQoNCmBgYHtyfQ0KY29tbXVuaXRpZXNFWElzbGFuZHMgPC0gbGFwcGx5KGNvbW11bml0aWVzRVgsIGZ1bmN0aW9uKHRpYiwgcG9vbHMsIG1hdHMsIGRtYXQpIHsNCiAgY29tYm4oDQogICAgbnJvdyh0aWIpLCAyLCANCiAgICBpc2xhbmRGVU4sDQogICAgZGF0ID0gdGliLCANCiAgICBwb29sID0gcG9vbHNbWw0KICAgICAgdGliJERhdGFzZXRJRFsxXQ0KICAgIF1dW1t0aWIkQ29tYm5OdW1bMV1dXSwNCiAgICBtYXQgPSBtYXRzW1sNCiAgICAgIHRpYiREYXRhc2V0SURbMV0NCiAgICBdXVtbdGliJENvbWJuTnVtWzFdXV0sDQogICAgZG1hdCA9IGRtYXQsDQogICAgc2ltcGxpZnkgPSBGQUxTRQ0KICApDQp9LCBwb29scyA9IHBvb2xzLCBtYXRzID0gbWF0cywgZG1hdCA9IG1hdHJpeChjKA0KICAwLCAxLCAwLCAjIElzbGFuZCAyIC0+IDENCiAgMSwgMCwgMSwgIyBJc2xhbmQgMSAtPiAyLCBJc2xhbmQgMyAtPiAyDQogIDAsIDEsIDAgICMgSXNsYW5kIDIgLT4gMw0KKSwgbnJvdyA9IDMsIG5jb2wgPSAzLCBieXJvdyA9IFRSVUUpKQ0KYGBgDQoNCjwhLS0gDQogIExvb2tpbmcgZ29vZCBzbyBmYXIuDQogIE5vdyB3ZSBuZWVkIHRvIGNvbnN0cnVjdCBhIGRhdGEgZnJhbWUgZm9yIGVhY2ggbGlzdCB3ZSBnZW5lcmF0ZWQuDQogIFRoZSBkYXRhZnJhbWUgc2hvdWxkIGhhdmUgdGltZSwgYWJ1bmRhbmNlLCBzcGVjaWVzLCBpc2xhbmQsIGFuZCBuYXRpdmUvZW5kZW1pYy9pbnZhZGVyLg0KICBXZSBjcmVhdGUgYSBnZ3Bsb3Qgd2l0aCByb3dzIGFzIGlzbGFuZHMsIGNvbHVtbnMgYXMgc3RhdHVzLCBjb2xvciBhcyBzcGVjaWVzLCBhYnVuZGFuY2UgYXMgeSwgdGltZSBhcyB4LiANCi0tPg0KDQpgYGB7cn0NCmNvbW11bml0aWVzRVhJc2xhbmRzTG9uZyA8LSBsYXBwbHkoDQogIGNvbW11bml0aWVzRVhJc2xhbmRzLCANCiAgZnVuY3Rpb24obGlzdHRpYiwgaXNsYW5kc051bSkgew0KICAgIHNwZWNpZXNOdW0gPC0gKG5jb2wobGlzdHRpYltbMV1dKSAtIDEpIC8gaXNsYW5kc051bQ0KICAgIA0KICAgIHJldHZhbCA8LSB0aWR5cjo6cGl2b3RfbG9uZ2VyKA0KICAgICAgbGlzdHRpYltbMV1dICU+JSBhcy5kYXRhLmZyYW1lLCANCiAgICAgIGNvbHMgPSAhInRpbWUiLCANCiAgICAgIG5hbWVzX3RvID0gIlNwZWNpZXMiLA0KICAgICAgdmFsdWVzX3RvID0gIkFidW5kYW5jZSINCiAgICApICU+JSBkcGx5cjo6bXV0YXRlKA0KICAgICAgU3BlY2llcyA9IGFzLm51bWVyaWMoU3BlY2llcyksDQogICAgICBJc2xhbmQgPSBmbG9vcigoU3BlY2llcyAtIDEpIC8gc3BlY2llc051bSksDQogICAgICBTcGVjaWVzID0gKChTcGVjaWVzIC0gMSkgJSUgc3BlY2llc051bSkgKyAxICMgbWFwcyAxLDIsMyw0ICUlIDQgLT4gMTo0DQogICAgKSAlPiUgZHBseXI6Omdyb3VwX2J5KA0KICAgICAgU3BlY2llcywgSXNsYW5kDQogICAgKSAlPiUgZHBseXI6Om11dGF0ZSgNCiAgICAgIE5hdGl2ZSA9IGRwbHlyOjpmaXJzdChBYnVuZGFuY2UgPiAwKSwNCiAgICAgIEludmFzaXZlID0gIU5hdGl2ZQ0KICAgICkgJT4lIGRwbHlyOjp1bmdyb3VwKCkgJT4lIGRwbHlyOjpncm91cF9ieSgNCiAgICAgIFNwZWNpZXMsIHRpbWUNCiAgICApICU+JSBkcGx5cjo6bXV0YXRlKA0KICAgICAgSXNsYW5kc09jY3VwaWVkID0gc3VtKEFidW5kYW5jZSA+IDApDQogICAgKSAlPiUgZHBseXI6OnVuZ3JvdXAoKSAlPiUgZHBseXI6Omdyb3VwX2J5KA0KICAgICAgU3BlY2llcywgSXNsYW5kDQogICAgKSAlPiUgZHBseXI6Om11dGF0ZSgNCiAgICAgIEVuZGVtaWMgPSBOYXRpdmUgJiBkcGx5cjo6Zmlyc3QoSXNsYW5kc09jY3VwaWVkKSA9PSAxLA0KICAgICAgVHlwZSA9IGRwbHlyOjpjYXNlX3doZW4oDQogICAgICAgIEVuZGVtaWMgfiAiRW5kZW1pYyIsDQogICAgICAgIE5hdGl2ZSB+ICJOYXRpdmUiLA0KICAgICAgICBJbnZhc2l2ZSB+ICJJbnZhc2l2ZSIsDQogICAgICAgIFRSVUUgfiAiT29wcyINCiAgICAgICkNCiAgICApDQogICAgDQogICAgcmV0dXJuKHJldHZhbCkNCiAgfSwgaXNsYW5kc051bSA9IDMNCikNCmBgYA0KDQpgYGB7cn0NCmNvbW11bml0aWVzRVhJc2xhbmRzSW1hZ2VzIDwtIGxhcHBseSgNCiAgY29tbXVuaXRpZXNFWElzbGFuZHNMb25nLA0KICBmdW5jdGlvbih0aWIpIHsNCiAgICBnZ3Bsb3QyOjpnZ3Bsb3QoDQogICAgICB0aWIsDQogICAgICBnZ3Bsb3QyOjphZXMoDQogICAgICAgIHggPSB0aW1lLA0KICAgICAgICB5ID0gQWJ1bmRhbmNlLA0KICAgICAgICBjb2xvciA9IGFzLmZhY3RvcihTcGVjaWVzKSwNCiAgICAgICAgIyBsaW5ldHlwZSA9IFR5cGUsDQogICAgICAgIGdyb3VwID0gaW50ZXJhY3Rpb24oU3BlY2llcywgSXNsYW5kKQ0KICAgICAgKQ0KICAgICkgKyBnZ3Bsb3QyOjpnZW9tX2xpbmUoDQogICAgKSArIGdncGxvdDI6OmZhY2V0X2dyaWQoDQogICAgICBJc2xhbmQgfiBUeXBlDQogICAgKSArIGdncGxvdDI6OnNjYWxlX3lfbG9nMTAoDQogICAgKQ0KICB9ICANCikNCmBgYA0KDQojIyMgQ2FzZXMgey50YWJzZXR9DQoNCiMjIyMgSHlicmlkIFBlcnNpc3RzDQpgYGB7cn0NCmNvbW11bml0aWVzRVhJc2xhbmRzSW1hZ2VzW1sxXV0NCmBgYA0KICANCiMjIyMgSHlicmlkIENvbGxhcHNlDQpgYGB7cn0NCmNvbW11bml0aWVzRVhJc2xhbmRzSW1hZ2VzW1syXV0NCmBgYA0KICANCiMjIyMgSHlicmlkIEV4dGluY3RzDQpgYGB7cn0NCmNvbW11bml0aWVzRVhJc2xhbmRzSW1hZ2VzW1szXV0NCmBgYA0KICANCiMjIyMgQ29sb25pZXMNCmBgYHtyfQ0KY29tbXVuaXRpZXNFWElzbGFuZHNJbWFnZXNbWzRdXQ0KYGBgDQogIA0KIyMjIyBEb21pbmF0aW9uDQpgYGB7cn0NCmNvbW11bml0aWVzRVhJc2xhbmRzSW1hZ2VzW1s1XV0NCmBgYA0KICANCg==